package de.tuhh.simsearch.model.persistence.contentmgmt.eao;

import java.math.BigInteger;
import java.util.LinkedList;
import java.util.List;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import de.tuhh.simsearch.model.persistence.contentmgmt.eao.interfaces.ContentMgmtEAOInterface;
import de.tuhh.simsearch.model.persistence.contentmgmt.entities.CategoryEntity;
import de.tuhh.simsearch.model.persistence.contentmgmt.entities.FileEntity;

@Stateless
@LocalBean
public class ContentMgmtEAO implements ContentMgmtEAOInterface {

  @PersistenceContext private EntityManager em;

  public ContentMgmtEAO() {

  }

  // Constructor for JUnit
  public ContentMgmtEAO(EntityManager em) {

    this.em = em;
  }

  public List<FileEntity> getAllFileEntitys() {

    TypedQuery<FileEntity> qFile = em.createQuery("SELECT f FROM FileEntity f", FileEntity.class);
    List<FileEntity> results = qFile.getResultList();
    return results;
  }

  @Override
  public FileEntity getFileEntity(BigInteger id) {

    List<FileEntity> myFiles = null;
    FileEntity myFile = null;

    TypedQuery<FileEntity> qFile = em.createQuery("SELECT f FROM FileEntity f WHERE f.id = :id", FileEntity.class)
        .setParameter("id", id);

    myFiles = qFile.getResultList();
    if (myFiles.size() == 1) {
      myFile = myFiles.get(0);
    }

    return myFile;
  }

  public boolean addFileEntityToCategory(FileEntity entity, String categoryName, Integer contentID) {

    boolean rv = false;

    TypedQuery<CategoryEntity> qCategory = em.createQuery(
        "SELECT c FROM CategoryEntity c WHERE c.categoryName = :name AND c.contentID = :contentId", CategoryEntity.class)
        .setParameter("name", categoryName);
    qCategory.setParameter("contentId", contentID);
    List<CategoryEntity> catList = qCategory.getResultList();

    BigInteger id = entity.getId();
    TypedQuery<FileEntity> qFile = em.createQuery("SELECT f FROM FileEntity f WHERE f.id = :id", FileEntity.class)
        .setParameter("id", id);
    List<FileEntity> fileList = qFile.getResultList();

    if (fileList.size() == 1 && catList.size() == 1) {
      // user is a pending user and so another set is used to insert
      try {

        catList.get(0).addFile(fileList.get(0));

      } catch (Exception e) {

        e.printStackTrace();
        rv = false;
      }

      rv = true;

    } else {

      rv = false;
    }

    return rv; // true means only operation successful

  }

  @Override
  public boolean addFileEntity(FileEntity entity) {

    boolean returnvar = true;

    if (!isFileNameFree(entity.getFileName(), entity.getPath())) {
      returnvar = false;
    } else {

      try {

        // em.getTransaction().begin();
        em.persist(entity);
        // em.getTransaction().commit();
      } catch (Exception e) {

        e.printStackTrace();
        returnvar = false;
      }
    }
    return returnvar;

  }

  @Override
  public List<FileEntity> searchFiles(String srchStrg) {

    TypedQuery<FileEntity> qFiles = em.createQuery(
        "SELECT f FROM FileEntity f WHERE f.displayedFilename LIKE :filename", FileEntity.class).setParameter(
        "filename", "%" + srchStrg + "%");
    List<FileEntity> foundFiles = qFiles.getResultList();

    return foundFiles;
  }

  // ein file kann zu mehreren Kategorien gehören - z.B. Geschichte und Text

  /*@Override
  public List<FileEntity> searchFiles(List<CategoryEntity> categories) {

    List<FileEntity> filesMatchingAllCategories = new LinkedList<FileEntity>();

    TypedQuery<FileEntity> query = em.createQuery("SELECT f FROM FileEntity f", FileEntity.class);
    List<FileEntity> results = query.getResultList();

    for (FileEntity f : results) {
      if (compareCategories(categories, f.getFileName())) {
        // not necessary to give also the path since each file is even
        // selected
        FileEntity file = new FileEntity(f.getFileName(), f.getPath());

        filesMatchingAllCategories.add(file);
      }
    }
    if (filesMatchingAllCategories.isEmpty()) {
      return null;
    } else {
      return filesMatchingAllCategories;
    }
  }

  public boolean compareCategories(List<CategoryEntity> categories, String fileName) {
    boolean success = false;

    TypedQuery<CategoryEntity> query = em
        .createQuery("SELECT f.categories FROM FileEntity f WHERE f.filename = :fileName", CategoryEntity.class)
        .setParameter("fileName", fileName).setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache);

    List<CategoryEntity> results = query.getResultList();
    if (results.equals(categories)) {
      success = true;
    }

    
    return success;
  }*/
  @Override
  public List<FileEntity> searchFiles(List<CategoryEntity> categories) {
    
    List<FileEntity> filesMatchingACategory = new LinkedList<FileEntity>();
    
    for(CategoryEntity e : categories) {
      
      TypedQuery<FileEntity> query = em.createQuery("SELECT f FROM FileEntity f LEFT OUTER JOIN f.categories cats "
          + "WHERE cats.categoryName = :name AND cats.contentID = :id", FileEntity.class).setParameter("name", e.getCategoryName());
      query.setParameter("id", e.getContentID());
      
      filesMatchingACategory.addAll(query.getResultList());
    }
    
    return filesMatchingACategory;     
  }

  public boolean isFileNameFree(String filename, String path) {

    TypedQuery<FileEntity> query = em.createQuery(
        "SELECT f FROM FileEntity f WHERE f.filename = :filename AND f.path = :path", FileEntity.class).setParameter(
        "filename", filename);
    query.setParameter("path", path);
    List<FileEntity> results = query.getResultList();

    return results.isEmpty();
  }

  @Override
  public CategoryEntity getCategoryEntity(String categoryName, Integer contId) {

    List<CategoryEntity> myCategories = null;
    CategoryEntity myCategory = null;

    TypedQuery<CategoryEntity> qCategory = em.createQuery(
        "SELECT c FROM CategoryEntity c WHERE c.contentID = :cid AND c.categoryName = :cname", CategoryEntity.class)
        .setParameter("cid", contId);
    qCategory.setParameter("cname", categoryName);

    myCategories = qCategory.getResultList();
    if (myCategories.size() == 1) {
      myCategory = myCategories.get(0);
    }

    return myCategory;
  }

  @Override
  public boolean addCategoryEntity(CategoryEntity entity) {

    boolean returnvar = true;

    if (this.getCategoryEntity(entity.getCategoryName(), entity.getContentID()) != null) {
      returnvar = false;
    } else {

      try {
        em.persist(entity);
      } catch (Exception e) {

        e.printStackTrace();
        returnvar = false;
        // em.getTransaction().begin();
      }
    }
    return returnvar;

  }

  @Override
  public List<CategoryEntity> searchCategories(String srchStrg) {

    TypedQuery<CategoryEntity> qCategories = em.createQuery(
        "SELECT c FROM CategoryEntity c WHERE c.categoryName LIKE :cname", CategoryEntity.class).setParameter("cname",
        "%" + srchStrg + "%");
    List<CategoryEntity> foundCategories = qCategories.getResultList();

    return foundCategories;
  }

  @Override
  public boolean removeFileEntity(BigInteger id) {
    boolean success = false;
    FileEntity file = null;
    file = this.getFileEntity(id);
    
    if (file != null) {
      em.remove(file);
      success = true;
    }
    return success;

  }

  @Override
  public boolean removeCategoryEntity(String categoryName, Integer contentID, FileEntity fileEntity) {

    boolean returnvar = false;
    CategoryEntity category;

    category = this.getCategoryEntity(categoryName, contentID);

    BigInteger fileId = fileEntity.getId();
    TypedQuery<FileEntity> queryFile = em.createQuery("SELECT f FROM FileEntity f WHERE f.id = :id", FileEntity.class)
        .setParameter("id", fileId);
    List<FileEntity> fileList = queryFile.getResultList();
    
    if (fileList.size() == 1 && category != null) {
      try {
        fileList.get(0).removeCategory(category);
        returnvar = true;
      } catch (Exception e) {

        e.printStackTrace();
        returnvar = false;
      }
    }
    
    return returnvar;
  }

  @Override
  public boolean removeCategoryEntity(String categoryName, Integer contentID) {

    boolean success = false;
    
    List <CategoryEntity> entities = null;
    
    TypedQuery<CategoryEntity> queryCategories = em.createQuery(
        "SELECT c FROM CategoryEntity c WHERE c.contentID = :cid AND c.categoryName = :cname", CategoryEntity.class)
        .setParameter("cid", contentID);
    queryCategories.setParameter("cname", categoryName);
    
    entities = queryCategories.getResultList();
    
    if(entities.size() == 1) {
      
      em.remove(entities.get(0));
      success = true;
    }

    return success;
  }

  @Override
  public boolean updateCategoryEntity(String oldName, Integer oldContentID, String newName, Integer newContentID) {

    boolean success = false;

    TypedQuery<CategoryEntity> catEntityQuery = em.createQuery(
        "SELECT c FROM CategoryEntity c WHERE c.contentID = :cid AND c.categoryName = :cname", CategoryEntity.class)
        .setParameter("cid", oldContentID);
    catEntityQuery.setParameter("cname", oldName);
    List<CategoryEntity> catEnts = catEntityQuery.getResultList();
    
    if(catEnts.size() == 1) {
      
      CategoryEntity catEnt = catEnts.get(0);
      catEnt.setCategoryName(newName);
      catEnt.setContentID(newContentID);
      success = true;
    }

    return success;
  }

  @Override
  public List<FileEntity> searchFilesByDesc(String srchstrg) {

    TypedQuery<FileEntity> qFiles = em.createQuery(
        "SELECT f FROM FileEntity f WHERE f.description LIKE :description", FileEntity.class).setParameter(
        "description", "%" + srchstrg + "%");
    List<FileEntity> foundFiles = qFiles.getResultList();

    return foundFiles;
  }
}